#pragma once
#include <vector>
#include "mutex.hpp"
#include "sem.hpp"

namespace RingQueueModual
{
    using namespace std;
    using namespace MutexModel;
    using namespace SemModual;

    template <typename T>
    class RingQueue
    {
    public:
        RingQueue(int cap = 10) : _v(cap), _cap(cap), _data_sem(0), _block_sem(cap)
        {
        }
        void Push(T &data)
        {
            _data_sem.P();
            {
                LockGuard lock(_p_mutex);
                _v[_p_step++] = data;
                _p_step %= _cap;
                _block_sem.V();
            }
        }
        void Pop(T *out)
        {
            _block_sem.P();
            {
                LockGuard lock(_c_mutex);
                *out = _v[_c_step++];
                _c_step %= _cap;
                _data_sem.V();
            }
        }
        ~RingQueue()
        {
        }

    private:
        vector<T> _v;
        int _cap;
        int _c_step;
        int _p_step;
        Sem _data_sem;
        Sem _block_sem;
        Mutex _p_mutex;
        Mutex _c_mutex;
    };

}